package services

import (
	"crypto/tls"
	"fmt"
	"log"
	"strconv"
	"time"

	"gopkg.in/gomail.v2"
	"gorm.io/gorm"
)

// EmailConfig 邮件配置
type EmailConfig struct {
	SMTPHost     string
	SMTPPort     int
	SMTPUsername string
	SMTPPassword string
	FromEmail    string
	FromName     string
}

// EmailService 邮件服务
type EmailService struct {
	config EmailConfig
	db     *gorm.DB
}

// NewEmailService 创建邮件服务
func NewEmailService(config EmailConfig, db *gorm.DB) *EmailService {
	return &EmailService{
		config: config,
		db:     db,
	}
}

// SendReminderEmail 发送提醒邮件
func (es *EmailService) SendReminderEmail(to, productName, reminderType string, recordTime time.Time) error {
	// 每次发送前动态加载最新配置
	cfg, cfgErr := es.loadEmailConfigFromDB()
	if cfgErr != nil {
		return fmt.Errorf("邮件配置缺失或不完整: %v", cfgErr)
	}

	// 创建邮件
	m := gomail.NewMessage()
	m.SetHeader("From", m.FormatAddress(cfg.FromEmail, cfg.FromName))
	m.SetHeader("To", to)

	// 根据提醒类型设置主题和内容
	var subject, body string
	if reminderType == "in_storage" {
		subject = fmt.Sprintf("【入库提醒】物资 %s 已入库超过一周", productName)
		body = fmt.Sprintf(`
			<html>
			<body>
				<h2>入库提醒</h2>
				<p>您好，</p>
				<p>物资 <strong>%s</strong> 已于 <strong>%s</strong> 入库，现已超过一周时间。</p>
				<p>请及时检查该物资的使用情况。</p>
				<br>
				<p>此邮件由ERP系统自动发送，请勿回复。</p>
			</body>
			</html>
		`, productName, recordTime.Format("2006-01-02 15:04:05"))
	} else {
		subject = fmt.Sprintf("【出库提醒】物资 %s 已出库超过一周", productName)
		body = fmt.Sprintf(`
			<html>
			<body>
				<h2>出库提醒</h2>
				<p>您好，</p>
				<p>物资 <strong>%s</strong> 已于 <strong>%s</strong> 出库，现已超过一周时间。</p>
				<p>请及时确认该物资的使用情况。</p>
				<br>
				<p>此邮件由ERP系统自动发送，请勿回复。</p>
			</body>
			</html>
		`, productName, recordTime.Format("2006-01-02 15:04:05"))
	}

	m.SetHeader("Subject", subject)
	m.SetBody("text/html", body)

	// 发送邮件
	d := gomail.NewDialer(cfg.SMTPHost, cfg.SMTPPort, cfg.SMTPUsername, cfg.SMTPPassword)

	// 根据端口设置TLS配置
	if cfg.SMTPPort == 465 {
		// SSL连接
		d.SSL = true
	} else {
		// TLS连接
		d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	}

	if err := d.DialAndSend(m); err != nil {
		log.Printf("发送邮件失败: %v", err)
		return err
	}

	log.Printf("邮件发送成功: %s -> %s", cfg.FromEmail, to)
	return nil
}

// 动态加载数据库中的邮件配置，便于热更新
func (es *EmailService) loadEmailConfigFromDB() (EmailConfig, error) {
	var settings []struct {
		SettingKey   string
		SettingValue string
	}
	if err := es.db.Table("system_settings").
		Select("setting_key, setting_value").
		Where("setting_key LIKE ?", "email_%").
		Find(&settings).Error; err != nil {
		return EmailConfig{}, err
	}

	conf := map[string]string{}
	for _, s := range settings {
		conf[s.SettingKey] = s.SettingValue
	}

	host := conf["email_smtp_host"]
	username := conf["email_smtp_username"]
	password := conf["email_smtp_password"]
	fromEmail := conf["email_from_email"]
	fromName := conf["email_from_name"]
	if host == "" || username == "" || password == "" || fromEmail == "" {
		return EmailConfig{}, fmt.Errorf("请在系统设置中配置 SMTP 主机、端口、用户名、授权码、发件邮箱")
	}

	port := 465
	if ps := conf["email_smtp_port"]; ps != "" {
		if p, err := strconv.Atoi(ps); err == nil {
			port = p
		}
	}

	return EmailConfig{
		SMTPHost:     host,
		SMTPPort:     port,
		SMTPUsername: username,
		SMTPPassword: password,
		FromEmail:    fromEmail,
		FromName:     fromName,
	}, nil
}

// CheckAndSendReminders 检查并发送提醒邮件
func (es *EmailService) CheckAndSendReminders() error {
	// 查询超过一周的出入库记录
	oneWeekAgo := time.Now().AddDate(0, 0, -7)

	// 查询需要提醒的出入库记录
	var records []struct {
		ID          uint      `json:"id"`
		ProductID   uint      `json:"product_id"`
		Type        string    `json:"type"`
		Email       string    `json:"email"`
		ProductName string    `json:"product_name"`
		GmtCreate   time.Time `json:"gmt_create"`
	}

	err := es.db.Table("inventory_records ir").
		Select("ir.id, ir.product_id, ir.type, p.email, p.name as product_name, ir.gmt_create").
		Joins("LEFT JOIN products p ON ir.product_id = p.id").
		Where("ir.gmt_create < ? AND p.email != '' AND p.email IS NOT NULL", oneWeekAgo).
		Find(&records).Error

	if err != nil {
		return err
	}

	// 检查是否已经发送过提醒
	for _, record := range records {
		var existingReminder struct {
			ID uint
		}

		err := es.db.Table("email_reminders").
			Select("id").
			Where("record_id = ? AND reminder_type = ?", record.ID, record.Type).
			First(&existingReminder).Error

		// 如果已经发送过提醒，跳过
		if err == nil {
			continue
		}

		// 发送邮件
		reminderType := "in_storage"
		if record.Type == "out" {
			reminderType = "out_storage"
		}

		if err := es.SendReminderEmail(record.Email, record.ProductName, reminderType, record.GmtCreate); err != nil {
			log.Printf("发送提醒邮件失败: %v", err)
			continue
		}

		// 记录已发送的提醒
		emailReminder := struct {
			ProductID    uint      `gorm:"column:product_id"`
			RecordID     uint      `gorm:"column:record_id"`
			Email        string    `gorm:"column:email"`
			ReminderType string    `gorm:"column:reminder_type"`
			SentAt       time.Time `gorm:"column:sent_at"`
			GmtCreate    time.Time `gorm:"column:gmt_create"`
			GmtModified  time.Time `gorm:"column:gmt_modified"`
		}{
			ProductID:    record.ProductID,
			RecordID:     record.ID,
			Email:        record.Email,
			ReminderType: reminderType,
			SentAt:       time.Now(),
			GmtCreate:    time.Now(),
			GmtModified:  time.Now(),
		}

		es.db.Table("email_reminders").Create(&emailReminder)
	}

	return nil
}

// StartReminderScheduler 启动提醒调度器
func (es *EmailService) StartReminderScheduler() {
	ticker := time.NewTicker(24 * time.Hour) // 每天检查一次
	go func() {
		for {
			select {
			case <-ticker.C:
				log.Println("开始检查邮件提醒...")
				if err := es.CheckAndSendReminders(); err != nil {
					log.Printf("检查邮件提醒失败: %v", err)
				}
			}
		}
	}()
}
